package com.iakuil.app.common.redis.utils;

import com.iakuil.app.common.core.util.SpringUtils;
import lombok.experimental.UtilityClass;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Collections;
import java.util.List;

/**
 * 基于Redis的Geo工具类
 *
 * @author liukai
 */
@UtilityClass
public class GeoUtils {

    private final RedisTemplate<String, String> redisTemplate = SpringUtils.getBean("redisTemplate");

    /**
     * 添加节点及位置信息
     *
     * @param geoKey    geo key
     * @param pointName 位置点标识
     * @param longitude 经度
     * @param latitude  纬度
     */
    public static void geoAdd(String geoKey, String pointName, double longitude, double latitude) {
        Point point = new Point(longitude, latitude);
        redisTemplate.opsForGeo().add(geoKey, point, pointName);
    }

    /**
     * 按距离查询指定范围内节点
     *
     * @param geoKey     geo key
     * @param longitude  经度
     * @param latitude   纬度
     * @param radius     距离
     * @param metricUnit 距离单位，例如 Metrics.KILOMETERS
     * @param limit      返回数量
     * @return Geo查询结果列表
     */
    public static List<GeoResult<RedisGeoCommands.GeoLocation<String>>> findRadius(String geoKey, double longitude, double latitude, double radius, Metrics metricUnit, int limit) {
        // 设置检索范围
        Point point = new Point(longitude, latitude);
        Circle circle = new Circle(point, new Distance(radius, metricUnit));
        // 定义返回结果参数，如果不指定默认只返回content即保存的member信息
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
            .newGeoRadiusArgs().includeDistance().includeCoordinates()
            .sortAscending()
            .limit(limit);
        GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(geoKey, circle, args);
        return results == null ? Collections.emptyList() : results.getContent();
    }

    /**
     * 计算指定key下两个成员点之间的距离
     *
     * @param geoKey  geo key
     * @param member1 成员点1
     * @param member2 成员点2
     * @param unit    单位
     * @return 距离对象
     */
    public static Distance calDistance(String geoKey, String member1, String member2, RedisGeoCommands.DistanceUnit unit) {
        return redisTemplate.opsForGeo().distance(geoKey, member1, member2, unit);
    }

    /**
     * 根据成员点名称查询位置信息
     *
     * @param geoKey  geo key
     * @param members 名称数组
     * @return 位置列表
     */
    public static List<Point> geoPosition(String geoKey, String[] members) {
        return redisTemplate.opsForGeo().position(geoKey, members);
    }
}
